package com.example.yichuangyun.utils;


import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.OverScroller;

import androidx.coordinatorlayout.widget.CoordinatorLayout;

import com.google.android.material.appbar.AppBarLayout;

import java.lang.reflect.Field;

/**
 * 防止 AppBarLayout 滑动卡顿
 * https://blog.csdn.net/yuruiyin123/article/details/89452943
 */
public class AppBarLayoutBehavior extends AppBarLayout.Behavior {

	private static final String TAG = "CustomAppbarLayoutBehavior";

	private static final int TYPE_FLING = 1;

	private boolean isFlinging;
	private boolean shouldBlockNestedScroll;

	public AppBarLayoutBehavior(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
//		Log.d(TAG, "onInterceptTouchEvent:" + child.getTotalScrollRange());
		shouldBlockNestedScroll = false;
		if (isFlinging) {
			shouldBlockNestedScroll = true;
		}

		switch (ev.getActionMasked()) {
			case MotionEvent.ACTION_DOWN:
				stopAppbarLayoutFling(child);  //手指触摸屏幕的时候停止fling事件
				break;
		}

		return super.onInterceptTouchEvent(parent, child, ev);
	}

	/**
	 * 反射获取私有的flingRunnable 属性，考虑support 28以后变量名修改的问题
	 * @return Field
	 */
	private Field getFlingRunnableField() throws NoSuchFieldException {
		try {
			// support design 27及以下版本
			Class<?> headerBehaviorType = this.getClass().getSuperclass().getSuperclass();
			return headerBehaviorType.getDeclaredField("mFlingRunnable");
		} catch (NoSuchFieldException e) {
			// 可能是28及以上版本
			Class<?> headerBehaviorType = this.getClass().getSuperclass().getSuperclass().getSuperclass();
			return headerBehaviorType.getDeclaredField("flingRunnable");
		}
	}

	/**
	 * 反射获取私有的scroller 属性，考虑support 28以后变量名修改的问题
	 * @return Field
	 */
	private Field getScrollerField() throws NoSuchFieldException {
		try {
			// support design 27及以下版本
			Class<?> headerBehaviorType = this.getClass().getSuperclass().getSuperclass();
			return headerBehaviorType.getDeclaredField("mScroller");
		} catch (NoSuchFieldException e) {
			// 可能是28及以上版本
			Class<?> headerBehaviorType = this.getClass().getSuperclass().getSuperclass().getSuperclass();
			return headerBehaviorType.getDeclaredField("scroller");
		}
	}

	/**
	 * 停止appbarLayout的fling事件
	 * @param appBarLayout
	 */
	private void stopAppbarLayoutFling(AppBarLayout appBarLayout) {
		//通过反射拿到HeaderBehavior中的flingRunnable变量
		try {
			Field flingRunnableField = getFlingRunnableField();
			Field scrollerField = getScrollerField();
			flingRunnableField.setAccessible(true);
			scrollerField.setAccessible(true);

			Runnable flingRunnable = (Runnable) flingRunnableField.get(this);
			OverScroller overScroller = (OverScroller) scrollerField.get(this);
			if (flingRunnable != null) {
//				LogUtil.d(TAG, "存在flingRunnable");
				appBarLayout.removeCallbacks(flingRunnable);
				flingRunnableField.set(this, null);
			}
			if (overScroller != null && !overScroller.isFinished()) {
				overScroller.abortAnimation();
			}
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	@Override
	public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int type) {
//		LogUtil.d(TAG, "onStartNestedScroll");
		stopAppbarLayoutFling(child);
		return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes, type);
	}

	@Override
	public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed, int type) {
//		LogUtil.d(TAG, "onNestedPreScroll:" + child.getTotalScrollRange() + " ,dx:" + dx + " ,dy:" + dy + " ,type:" + type);

		//type返回1时，表示当前target处于非touch的滑动，
		//该bug的引起是因为appbar在滑动时，CoordinatorLayout内的实现NestedScrollingChild2接口的滑动子类还未结束其自身的fling
		//所以这里监听子类的非touch时的滑动，然后block掉滑动事件传递给AppBarLayout
		if (type == TYPE_FLING) {
			isFlinging = true;
		}
		if (!shouldBlockNestedScroll) {
			super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
		}
	}

	@Override
	public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dxConsumed, int dyConsumed, int
			dxUnconsumed, int dyUnconsumed, int type) {
//		LogUtil.d(TAG, "onNestedScroll: target:" + target.getClass() + " ," + child.getTotalScrollRange() + " ,dxConsumed:"
//				+ dxConsumed + " ,dyConsumed:" + dyConsumed + " " + ",type:" + type);
		if (!shouldBlockNestedScroll) {
			super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
		}
	}

	@Override
	public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl, View target, int type) {
//		Log.d(TAG, "onStopNestedScroll");
		super.onStopNestedScroll(coordinatorLayout, abl, target, type);
		isFlinging = false;
		shouldBlockNestedScroll = false;
	}
}